class ContactData
  attr_accessor :type_id, :value, :is_required, :name

  def initialize(type, value, is_required, name)
    @type_id = type
    @value = value
    @is_required = is_required
    @name = name
  end
end

class AddressData
  attr_accessor :type, :data

  #Type is the User Address Type table data
  #Data is the Address table data 
  def initialize(type, data)
    @type = type
    @data = data
  end
end

module UserData
  include Utils::Url
  include Utils::Text
  protected
    def gather_additional_user_info
      gather_contact_info if @user.role.gather_contact_info
      gather_address_info if @user.role.gather_address_info
    end

    def gather_additional_user_info_for_show
      gather_contact_info_for_show if @user.role.gather_contact_info
      gather_address_info_for_show if @user.role.gather_address_info
    end

    def gather_additional_user_info_from_post
      params[:user].delete(:id)
      check_for_updated_password
      @user.attributes=(params[:user])
      gather_user_groups_from_post
      gather_contact_info_from_post if @user.role.gather_contact_info
      gather_address_info_from_post if @user.role.gather_address_info
    end 

    def check_for_updated_password
      if params[:user][:password]
        validate_password
        params[:user][:password] = Security::Encryption.encrypt(params[:user][:password])
        params[:user][:password_confirmation] = Security::Encryption.encrypt(params[:user][:password_confirmation])
      end
    end

    def validate_password
      if params[:user][:password] != params[:user][:password_confirmation] 
        @user.errors.add(:password, "Password not confirmed")
      else
        if !(params[:user][:password] =~  /^.*(?=.{6,})((?=.*\d)|(?=.*[A-Z])|(?=.*[!@#$\%^&*()_+}{"":;'?\/>.<,])).*$/)
          @user.errors.add(:password, "Password must be at least 6 characters long and must contain:<br/>1 Number or..<br/>1 Capital Letter or..<br/>1 Special Character")
        end
      end
    end

    def update_additional_user_info
      update_contact_info if @user.role.gather_contact_info
      update_address_info if @user.role.gather_address_info
    end


    def gather_contact_info_for_show
      unless @user.user_contact
        @contacts = []
        return 
      end
      gather_contact_info
    end

    def gather_contact_info
      @contacts = []
      UserContactType.find(:all,:conditions => ["is_active is true"]).each{|ctype|
        uc =  @user.find_contact_by_type(ctype.id)
        value = nil
        value = uc.value unless uc.nil?
        @contacts << ContactData.new(ctype.id, value, ctype.is_required, ctype.name)
      }
    end

    def gather_user_groups_from_post
      #clear orphans
      ugroups = @user.user_group.dup
      ugroups.each do |usr_grp|
        @user.user_group.delete(usr_grp) unless param?("grp_#{usr_grp.id}")
      end

      params.each do |key,value|
        if key =~ /^grp_/
          grp_id = get_id_from_param(key)
          @user.user_group << UserGroup.find(grp_id) unless @user.has_user_group_id?(grp_id)
        end
      end
    end

    def gather_contact_info_from_post
      @contacts = []
      UserContactType.find(:all,:conditions => ["is_active is true"]).each{|ctype|
        pcontact =  params["contact_#{ctype.id}"]
        validate_contact_info?(ctype,pcontact)
        @contacts << ContactData.new(ctype.id, pcontact, ctype.is_required, ctype.name)
      }
    end

    def update_contact_info
      UserContactType.find(:all,:conditions => ["is_active is true"]).each{|ctype|
        pcontact =  params["contact_#{ctype.id}"]
        if validate_contact_info?(ctype,pcontact)
          if empty_or_nil?(pcontact)
            @user.remove_contact_by_type(ctype.id)
          else
            ucontact =  @user.find_contact_by_type(ctype.id)
            updater_id = current_updater_id
            #Registering a user..so the updater id is the new user.
            updater_id = @user.id if updater_id == -1
            if ucontact.nil?
              @user.user_contact.create(:user_contact_type_id => ctype.id,
                                        :value => pcontact, :updated_by => updater_id)
            else
              ucontact.value = pcontact
              ucontact.save
            end
          end
        end
      }
    end

    def validate_contact_info?(ctype,pcontact)
      if ctype.is_required
        if empty_or_nil?(pcontact)
          @user.errors.add_to_base("#{ctype.name} is required")
          return false
        end
      end
      unless empty_or_nil?(pcontact)
        rx = Regexp.new(ctype.contact_format.format_rule)
        unless rx =~ pcontact
          @user.errors.add_to_base("#{ctype.name} is not valid")
          return false
        end
      end
      return true
    end

    def gather_address_info_for_show
      unless @user.user_address
        @addresses = []
        return 
      end
      gather_address_info
    end

    def gather_address_info
      @addresses = []
      @add_addresses = []
      UserAddressType.find(:all,:conditions => ["is_active is true"]).each{|uat|
        ua =  @user.find_address_by_type(uat.id)
        if ua.nil? && uat.is_required
          @addresses << AddressData.new(uat,Address.new)
        elsif !ua.nil?
          @addresses << AddressData.new(uat,Address.find(ua.address_id)) 
        else
          @add_addresses << uat
        end
      }
    end

    def gather_address_info_from_post
      @addresses = []
      @add_addresses = []
      UserAddressType.find(:all,:conditions => ["is_active is true"]).each{|uat|
        paddr =  params["address_#{uat.id}"]
        unless paddr.nil?
          validate_address_info?(uat,paddr)
          addr = Address.new(:line_one => paddr["line_one"],
                            :line_two=> paddr["line_two"],
                            :city => paddr["city"],
                            :state_cd => paddr["state_cd"],
                            :zip_code => paddr["zip_code"])
          @addresses << AddressData.new(uat,addr)            
        else
          if int_param_eql?("add_address",uat.id)
            @addresses << AddressData.new(uat,Address.new)            
          else
            @add_addresses << uat
          end
        end
      }
    end

    def update_address_info
      UserAddressType.find(:all,:conditions => ["is_active is true"]).each{|uat|
        paddr =  params["address_#{uat.id}"]
        if validate_address_info?(uat,paddr)
          if paddr.nil? || address_is_blank?(paddr)
            @user.remove_address_by_type(uat.id)
          else
            ua =  @user.find_address_by_type(uat.id)
            if ua.nil?
              new_addr = Address.new(:line_one => paddr["line_one"],
                                      :line_two => paddr["line_two"],
                                      :city => paddr["city"],
                                      :state_cd => paddr["state_cd"],
                                      :zip_code => paddr["zip_code"],
                                      :updated_by => current_updater_id)
              new_addr.save
              @user.user_address.create(:user_address_type_id => uat.id,
                                        :address_id => new_addr.id,
                                       :updated_by => current_updater_id)
            else
              ua.updated_by = current_updater_id
              ua.address.line_one = paddr["line_one"]
              ua.address.line_two = paddr["line_two"]
              ua.address.city = paddr["city"]
              ua.address.state_cd = paddr["state_cd"]
              ua.address.zip_code = paddr["zip_code"]
              ua.address.updated_by = current_updater_id
              ua.address.save
              ua.save
            end
          end #test to remove
        end #validated?
      }
    end

    def validate_address_info?(addr_type, addr)
      return true if addr.nil?

      if addr_type.is_required
        if empty_or_nil?(addr["line_one"])
          @user.errors.add_to_base("#{addr_type.name} address is required")
        end
        if empty_or_nil?(addr["city"])
          @user.errors.add_to_base("#{addr_type.name} city is required")
        end
        if empty_or_nil?(addr["state_cd"])
          @user.errors.add_to_base("#{addr_type.name} state is required")
        end
        if empty_or_nil?(addr["zip_code"])
          @user.errors.add_to_base("#{addr_type.name} zip is required")
        end
      elsif address_is_incomplete?(addr)
          @user.errors.add_to_base("#{addr_type.name} address is incomplete. <br/> address, city, state and zip are required for a complete address.") unless address_is_blank?(addr)
      end

      if !empty_or_nil?(addr["zip_code"])
        @user.errors.add_to_base("#{addr_type.name} zip format is 12345-1234. <br/> The zip 4 portion is optional.") unless addr["zip_code"] =~ /^\d{5}(-\d{4})?$/
      end

      if !empty_or_nil?(addr["city"])
        @user.errors.add_to_base("#{addr_type.name} city is invalid.") unless addr["city"] =~ /^[a-zA-Z]+$/
      end

      return false unless @user.errors.empty?
      return true
    end

    def gather_user_group_info(objeck)
      ugroups = objeck.user_group.dup
      ugroups.each do |ug|
        objeck.user_group.delete(ug) unless param?("grp_#{ug.id}")
      end

      params.each do |key,value|
        if key =~ /^grp_/
          grp_id = get_id_from_param(key)
          objeck.user_group << UserGroup.find(grp_id) unless objeck.has_user_group_id?(grp_id)
        end
      end
    end

    private
      def address_is_blank?(paddr)
        empty_or_nil?(paddr["line_one"]) && 
          empty_or_nil?(paddr["line_two"]) &&
          empty_or_nil?(paddr["city"]) &&
          empty_or_nil?(paddr["state_cd"]) &&
          empty_or_nil?(paddr["zip_code"])
      end

      def address_is_incomplete?(paddr)
        empty_or_nil?(paddr["line_one"]) ||
          empty_or_nil?(paddr["city"]) ||
          empty_or_nil?(paddr["state_cd"]) ||
          empty_or_nil?(paddr["zip_code"])
      end

end
